package paginator.classes
{
	import flash.events.EventDispatcher;
	import flash.events.MouseEvent;
	
	import mx.collections.ArrayCollection;
	import mx.controls.Button;
	import mx.controls.TextInput;
	import mx.utils.ObjectUtil;
	
	import paginator.Paginator;
	import paginator.buttons.IndexBtn;
	import paginator.helpers.ArrayUtils;
	import paginator.helpers.ParserCss;
	import paginator.paginateEvents.PagesValueChange;
	import paginator.paginateEvents.PaginateEvent;
	

	public class PaginatorManager extends EventDispatcher
	{
		
		//---------------------------------------------------------------
		// <------ PUBLIC & PRIVATE CONSTS ------>
		//---------------------------------------------------------------
		//{
		//public static const TOTAL_ITEMS_CHANGE:String = "totalItemsChange";
		
		public static const CSS_PATH:String = "StyleButtons.css";
		
		//This private consts specify name of class in css file
		
		private const INDEX_CLASSNAME:String = ".indexBtn";
		private const SEPARATOR_CLASSNAME:String = ".separatorBtn";
		private const NEXT_CLASSNAME:String = ".nextButton";
		private const PREVIOUS_CLASSNAME:String = ".previousButton";
		private const LAST_CLASSNAME:String = ".lastButton";
		private const FIRST_CLASSNAME:String = ".firstButton";
		private const FORWARD_CLASSNAME:String = ".jumpForward";
		private const BACK_CLASSNAME:String = ".jumpBack";
		private const COUNT_CLASSNAME:String = ".countButton";
		//}
		//---------------------------------------------------------------
		// <------ PRIVATE PROPERTIES ------>
		//---------------------------------------------------------------
		//{
		private var _paginator:Paginator;
		private var _selectedPage:int = 0;
		private var _pages:int = 0;
		private var _selectionColor:String = "#16711935";
		private var _offset:int = 0;
		private var _pageToDisplay:int = 0;
		private var _totalItems:int = 0;
		private var _itemsPerPage:int = 0;
		private var _indexBtnsWidth:int = 25;
		
		/**
		 * Specify the number of center page
		 */		
		private var _centerValue:int;
		private var _selectedIndex:int = 0;
		/**
		 * Parser for StyleButtons file 
		 */		
		private var _parserCss:ParserCss;

		/**
		 * Width separator button 
		 */		
		private var _separatorBtnWidth:int = 35;
		/**
		 * Height separator button 
		 */			
		private var _separatorBtnHeight:int = 25;
		/**
		 * Width count button 
		 */		
		private var _countBtnWidth:int = 25;
		/**
		 * Height count button 
		 */			
		private var _countBtnHeight:int = 25;
		
		private var _navigateButtonWidth:int = 35;
		
		private var _clickedButtonIndex:int = -1;

		//}
		//---------------------------------------------------------------
		// <------ PUBLIC PROPERTIES ------>
		//---------------------------------------------------------------
		//{

	
		/**
		 *Determines selection color 
		 *This property set only in ActionScript code
		 */
		public function set selectionColor(value:uint):void
		{
			
			_selectionColor = "#" + value.toString(16);
		}

		/**
		 * Paginator control
		 * 
		 * @return Paginator 
		 */		
		public function get paginator():Paginator
		{
			return _paginator;
		}
		
		/**
		 * @private
		 */		
		public function set paginator(value:Paginator):void
		{
			_paginator = value;
		}

		/**
		 * Selected page
		 *  
		 * @return int
		 */		
		public function get selectedPage():int
		{
			return _selectedPage;
		}
		
		/**
		 * 
		 * @private
		 */		
		public function set selectedPage(value:int):void
		{
			if (ObjectUtil.numericCompare(value, _selectedPage) != 0 && 
				value >= 1 &&
				value <= _pages)
			{
				var tempSelectedPage:int = _selectedPage;
				var tempBtn:IndexBtn = retrieveSelectedBtn(_selectedIndex);
				var labelValue:int = int(tempBtn.label);
				
				var tempOffset:int = value - labelValue;
				tempSelectedPage += tempOffset;

				if (_centerValue > 1)
				{
					if (value > labelValue)
					{
						if (!((tempSelectedPage + _centerValue - 1) > _pages) && !((tempSelectedPage - _centerValue - 1) < 0))
						{
							offset = tempOffset;
						}
					}
					else if (value < labelValue)
					{
						if (!((tempSelectedPage - _centerValue) < 0) && !((tempSelectedPage + _centerValue - 1) >= _pages))
						{
							offset = tempOffset;
						}
					}
				}
				tempBtn = retrieveSelectedBtn(-1, String(tempSelectedPage));
				if (tempBtn)
				{
					_selectedPage = tempSelectedPage;
					_selectedIndex = tempBtn.index;
					
					var paginateEvent:PaginateEvent = new PaginateEvent(PaginateEvent.SELECTED_PAGE_CHANGED);
					paginateEvent.selectedPage = _selectedPage;
					_paginator.dispatchEvent(paginateEvent);
				}
			}
			updateElements();
		}
		
		/**
		 * Number of pages 
		 */		
		public function get pages():int
		{
			return _pages;
		}
		
		/**
		 *Jump value
		 *If offset is grater than 0 jump forrward 
		 *If offset is less than 0 jump back
		 * 
		 * @private
		 */
		public function set offset(value:int):void
		{
			var tempSelectedPage:int = _selectedPage;
			tempSelectedPage += value;
			if (value > 0)
			{
				_offset = value;
				
				if (!((tempSelectedPage - _centerValue) < 0))
				{
					if (_offset >= _centerValue - 1)
					{
						_selectedIndex = _centerValue - 1;	
					}
					
					offsetButtons();
				}
				
				if ((tempSelectedPage + _centerValue - 1) > _pages)
				{
					selectLastOrFirstPage(1);
				}
			}
			else if (value < 0)
			{
				_offset = value;
				if (!((tempSelectedPage + _centerValue) > _pages))
				{
					if (int(Math.abs(_offset)) >= _centerValue - 1)
					{
						_selectedIndex = _centerValue - 1;
					}
					offsetButtons();
				}
				
				if ((tempSelectedPage - _centerValue) < 0)
				{
					selectLastOrFirstPage(0);
				}
			}
			else
			{
				_offset = 0;
			}
			
			if (_offset)
			{
				var tempBtn:IndexBtn = retrieveSelectedBtn(-1, String(tempSelectedPage));
				if (tempBtn)
				{
					_selectedPage = tempSelectedPage;
					_selectedIndex = tempBtn.index;
					
					var paginateEvent:PaginateEvent = new PaginateEvent(PaginateEvent.SELECTED_PAGE_CHANGED);
					paginateEvent.selectedPage = _selectedPage;
					_paginator.dispatchEvent(paginateEvent);
				}
			}
			
			updateElements();
		}
		
		
		/**
		 * Returns the number of items per page
		 * 
		 * @return int 
		 */		
		public function get pageToDisplay():int
		{
			return _pageToDisplay;
		}
		
		/**
		 * 
		 * @private
		 */		
		public function set pageToDisplay(value:int):void
		{
			var indexBtn:IndexBtn = null;
			var ceilCenterValue:int = Math.ceil(_pages / 2);
			var displayPage:int = value;

			_paginator.ID_ContainerBtns.removeAllChildren();
			if (value % 2 == 0 && _pages > value)
			{
				displayPage += 1;
			}
			
			//_selectedPage = value / 2 + 1;
			_selectedPage = 1;
			if (_pages > value)
			{
				_centerValue = value / 2 + 1;
			}
			else
			{
				displayPage = _pages;
				_centerValue = ceilCenterValue <= _pages ? ceilCenterValue : _pages;
			}
			
			
			for (var i:int = 0; i < displayPage; i++)
			{
				indexBtn = new IndexBtn();
				indexBtn.addEventListener(MouseEvent.CLICK, onClickIndexBtn);
				indexBtn.minWidth = _indexBtnsWidth;
				indexBtn.width = _indexBtnsWidth;
				_parserCss.btnObjects(indexBtn, INDEX_CLASSNAME);
				if ((i + 1) == _selectedPage)
				{
					indexBtn.setStyle("borderColor", _selectionColor);
					indexBtn.setStyle("fontStyle", "italic");
					indexBtn.setStyle("textDecoration", "underline");
					_selectedIndex = i;
				}
				
				_paginator.ID_ContainerBtns.addChildAt(indexBtn, i);
				indexBtn.label = (i + 1).toString();
		
				if (!_countBtnHeight && !_separatorBtnHeight)
				{
					_countBtnHeight = indexBtn.height;
					_separatorBtnHeight = indexBtn.height;
				}
			}
			
			_pageToDisplay = value;
			
			updateElements();
		}
		
		/**
		 * Specify amount of all items/pages
		 * 
		 * @return int
		 */		
		public function get totalItems():int
		{
			return _totalItems;
		}
		
		/**
		 * 
		 * @private
		 */		
		public function set totalItems(value:int):void
		{
			this._totalItems = value;
			
			_paginator.ID_NextButtons.isMenuRefresh = true;
			_paginator.ID_PreviousButtons.isMenuRefresh = true;
		}
		
		/**
		 *Number of items per page 
		 */
		public function get itemsPerPage():int
		{
			return _itemsPerPage;
		}
		
		/**
		 * @private
		 */
		public function set itemsPerPage(value:int):void
		{
			_itemsPerPage = value;
			
			_paginator.ID_NextButtons.isMenuRefresh = true;
			_paginator.ID_PreviousButtons.isMenuRefresh = true;
			
			updateElements();
		}
		
		/**
		 * Specify width for buttons with number of page
		 * 
		 * @return int 
		 */		
		public function get indexBtnsWidth():int
		{
			return _indexBtnsWidth;
		}
		
		/**
		 * 
		 * @param value
		 */		
		public function set indexBtnsWidth(value:int):void
		{
			_indexBtnsWidth = value;	
		}
		
		public function get numOfPages():int
		{
			return int(Math.ceil(_totalItems / _itemsPerPage));
		}
		//}
		//---------------------------------------------------------------
		// <------ PUBLIC METHODS ------>
		//---------------------------------------------------------------
		//{
		
		/**
		 * Ctor
		 *  
		 * @param Paginator paginatorControl Paginator object
		 * @param parserCss parser css for button style
		 */		
		public function PaginatorManager(paginatorControl:Paginator = null, parserCss:ParserCss = null)
		{
			this._parserCss = parserCss;
			this._paginator = paginatorControl;
			
			
			_parserCss.btnObjects(_paginator.ID_CountElement, INDEX_CLASSNAME);
			_parserCss.btnObjects(_paginator.ID_SeparatorCount, SEPARATOR_CLASSNAME);
			_parserCss.btnObjects(_paginator.ID_First, FIRST_CLASSNAME);
			_parserCss.btnObjects(_paginator.ID_Last, LAST_CLASSNAME);
			_parserCss.btnObjects(_paginator.ID_NextButtons.ID_Next, NEXT_CLASSNAME);
			_parserCss.btnObjects(_paginator.ID_PreviousButtons.ID_Previous, PREVIOUS_CLASSNAME);
			_parserCss.btnObjects(_paginator.ID_NextButtons.ID_SkipNext, FORWARD_CLASSNAME);
			_parserCss.btnObjects(_paginator.ID_PreviousButtons.ID_SkipPrevious, BACK_CLASSNAME);
			_parserCss.btnObjects(_paginator.ID_CountElement, COUNT_CLASSNAME);
			
			_paginator.ID_CountElement.addEventListener(MouseEvent.CLICK, onClickCountButton);
		}
		
		/**
		 * Refresh buttons paginator
		 * 
		 */		
		public function updateElements():void
		{
			var numOfpages:int = Math.ceil(_totalItems / _itemsPerPage);
			if (_pages != numOfpages)
			{
				_pages = numOfpages;

				var numOfPages:PagesValueChange = new PagesValueChange(PagesValueChange.NUMBEROFPAGES_CHANGE);
				numOfPages.numberOfPages = _pages;

				dispatchEvent(numOfPages);
			}
			
			_paginator.ID_CountElement.label = _pages.toString();
			_paginator.ID_CountElement.height = _countBtnHeight;
		
			if (_pages >= 10)
			{
				_paginator.ID_TextInput.text = _pages.toString();
				_paginator.ID_TextInput.validateNow();
				_paginator.ID_CountElement.width = _paginator.ID_TextInput.textWidth * 2;
			}
			else
			{
				_paginator.ID_CountElement.width = _countBtnWidth;
			}

			_paginator.ID_SeparatorCount.height = _separatorBtnHeight;
			_paginator.ID_SeparatorCount.width = _separatorBtnWidth;
			_paginator.ID_First.width = _navigateButtonWidth;
			_paginator.ID_Last.width = _navigateButtonWidth;
			_paginator.ID_PreviousButtons.ID_Previous.width = _navigateButtonWidth;
			_paginator.ID_PreviousButtons.ID_SkipPrevious.width = _navigateButtonWidth;
			_paginator.ID_NextButtons.ID_Next.width = _navigateButtonWidth;
			_paginator.ID_NextButtons.ID_SkipNext.width = _navigateButtonWidth;
			
			if (_selectedPage > _pages || _selectedPage < 0)
			{
				return;	
			}
			
			var selectedBtn:IndexBtn = retrieveSelectedBtn(_selectedIndex);
			var tempBtn:IndexBtn = null;
			var btnsArr:Array = _paginator.ID_ContainerBtns.getChildren();
			var count:int = ArrayUtils.getCount(btnsArr);
			var i:int;
			if (selectedBtn)
			{
				for (i = 0; i < count; i++)
				{
					tempBtn = btnsArr[i];
					tempBtn.clearStyle("textDecoration");
					tempBtn.clearStyle("fontStyle");
					tempBtn.clearStyle("borderColor");
					_parserCss.btnObjects(tempBtn, INDEX_CLASSNAME);
				}
				selectedBtn.setStyle("borderColor", _selectionColor);
				selectedBtn.setStyle("fontStyle", "italic");
				selectedBtn.setStyle("textDecoration", "underline");
			}
		}

		/**
		 * Select last or first page
		 *  
		 * @param int typeSelection If equals 0 select first page, If equals 1 select last page
		 */		
		public function selectLastOrFirstPage(typeSelection:int):void
		{
			var i:int;
			var tempBtn:IndexBtn = null;
			var btnsArr:Array = _paginator.ID_ContainerBtns.getChildren();
			var count:int = ArrayUtils.getCount(btnsArr);
			var tempPages:int = _pages;
			var paginateEvent:PaginateEvent;
			
			i = typeSelection == 0 ? 0 : count - 1;
			if (count)
			{
				switch (typeSelection)
				{
					case 0:
						for (i = 0; i < count; i++)
						{
							tempBtn = btnsArr[i];
							tempBtn.label = String(i + 1);
						}
						_selectedPage = 1;
						_selectedIndex = 0;
						
						paginateEvent = new PaginateEvent(PaginateEvent.SELECTED_PAGE_CHANGED);
						paginateEvent.selectedPage = _selectedPage;
						_paginator.dispatchEvent(paginateEvent);
						
						break;
					case 1:
						for (i = count - 1; i >= 0; i--)
						{
							tempBtn = btnsArr[i];
							tempBtn.label = String(tempPages--);
						}
						_selectedPage = _pages;
						_selectedIndex = count - 1;
						
						paginateEvent = new PaginateEvent(PaginateEvent.SELECTED_PAGE_CHANGED);
						paginateEvent.selectedPage = _selectedPage;
						_paginator.dispatchEvent(paginateEvent);	
						
						break;
				}
				
				updateElements();
			}
		}
		//}
		//---------------------------------------------------------------
		// <------ PRIVATE METHODS ------>
		//---------------------------------------------------------------
		//{
		/**
		 * This function is called when user click on page button
		 *  
		 * @param MouseEvent event
		 */		
		private function onClickIndexBtn(event:MouseEvent):void
		{
			var target:IndexBtn = event.currentTarget as IndexBtn;
			selectedPage = int(target.label);
		}
		
		/**
		 * This function is called when user click on maximum page button 
		 * 
		 * @param MouseEvent event
		 */		
		private function onClickCountButton(event:MouseEvent):void
		{
			if (_selectedPage != _pages)
			{
				selectLastOrFirstPage(1);
				updateElements();
			}
		}
		/**
		 * Find and return object of selected button
		 * If selIndex equal -1 then function find element by labelButton
		 *  
		 * @param int selIndex Index of button in container
		 * @param String labelButton Label on button
		 *  
		 * @return IndexBtn 
		 */		
		private function retrieveSelectedBtn(selIndex:int = -1, labelButton:String = null):IndexBtn
		{
			var selectedBtn:IndexBtn = null;
			var arr:Array = _paginator.ID_ContainerBtns.getChildren();
			var tempArr:Array = null;
			var filter:Function = function (btn:IndexBtn, ind:int, arrBtns:Array):Boolean
			{
				return btn.label == labelButton;
			}
				
			if (ArrayUtils.isEmpty(arr))
			{
				return null;
			}
			
			if (selIndex != -1)
			{
				return arr[selIndex];
			}
			
			tempArr = arr.filter(filter);
			if (!ArrayUtils.isEmpty(tempArr))
			{
				selectedBtn = tempArr.shift();
			}
			
			return selectedBtn;
		}
		
		/**
		 * This funciton offset number on button forrward or back 
		 */		
		private function offsetButtons():void
		{
			var i:int;
			var tempBtn:IndexBtn = null;
			var tempSelectedPage:int = _selectedPage;

			var btnsArr:Array = _paginator.ID_ContainerBtns.getChildren();
			var count:int = ArrayUtils.getCount(btnsArr);
			var btnValue:int;
			
			if (ArrayUtils.isEmpty(btnsArr))
			{
				return;
			}
			
			tempSelectedPage += _offset;
			btnValue = tempSelectedPage;
			tempBtn = retrieveSelectedBtn(_selectedIndex);
			//Set number on button from selected button to end
			for (i = tempBtn.index; i < count; i++)
			{
				tempBtn = btnsArr[i];
				tempBtn.label = String(btnValue++);
			}
			
			tempBtn = retrieveSelectedBtn(_selectedIndex);
			btnValue = tempSelectedPage;
			//Set number on button from selected button to start
			for (i = tempBtn.index; i >= 0; i--)
			{
				tempBtn = btnsArr[i];
				tempBtn.label = String(btnValue--);
			}
			
			_clickedButtonIndex = -1;
		}

		//}
	}
}